#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 5e3 + 10;
int n, w;
vector<int> vv[maxn];
int weight[maxn]; // 记录该气球头顶上面的绳子的权重
int arr[maxn];
int sz[maxn]; // 记录每个节点的子树节点的个数
int dp[maxn][maxn]; // 以 i 为根节点的子树中获取 j 个气球最少需要的力气

void dfs(int n, int p){
	sz[n]=1;
	for(auto child:vv[n]){
		if(child==p){
			continue;
		}
		dfs(child, n);
		sz[n]+=sz[child];
		// 转移方程
		for(int j=sz[n];j>=0;j--){ // 当前节点获得气球个数 , 这里必须倒着遍历, 不然会重复计算某个气球
			// 比如 dp[3][1] = dp[2][1] 了
			// dp[3][2]=dp[3][2-1]+dp[2][1] , 这就导致都是从  2 转移过来的, 重复了, 
			// 但是倒序的话, 最多只可能使用一次 dp[2][1]
			// 因为 dp[3][2]=dp[3][2-1]+dp[2][1], 中 dp[3][1] 不可能从  dp[2][1] 转移过来, 只能从之前的节点转移过来
			for(int k=0;k<=min(j, sz[child]);k++){ // 子节点获得气球个数 注意 这里面 k<=min(j, sz[child]), 不要写错了
				dp[n][j]=min(dp[n][j], dp[n][j-k]+dp[child][k]);
				dp[n][j]=min(dp[n][j], dp[child][j]);
			}
		}
	}
	
	dp[n][sz[n]-1]=min(dp[n][sz[n]-1], arr[n]); // 把此气球扎破
	dp[n][sz[n]]=min(dp[n][sz[n]], weight[n]); // 把此气球头上绳子剪断
}


void solve(){
	memset(dp, 0x3f, sizeof(dp));
	cin>>n>>w;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
		dp[i][0]=0;
	}
	for(int i=2;i<=n;i++){
		int u, w;
		cin>>u>>w;
		vv[i].push_back(u);
		vv[u].push_back(i);
		weight[i]=w;
	}
	
	weight[1]=1e18;
	dfs(1, 0);
	for(int i=n;i>=0;i--){
		if(dp[1][i]<=w){
			cout<<i<<'\n';
			break;
		}
	}
}

signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	solve();
	return 0;
}
